﻿# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from datetime import datetime, date

from collections import OrderedDict
from django.contrib import admin
from django.http import HttpResponse
from django.conf import settings
from openpyxl import Workbook
from dateutil import parser
from daterange_filter.filter import DateRangeFilter
from dateutil.relativedelta import relativedelta
from import_export import resources, fields
from import_export.admin import ImportMixin, ExportMixin, ImportExportMixin
from import_export.widgets import ManyToManyWidget, ForeignKeyWidget
from import_export.results import Result, RowResult
from xpinyin import Pinyin

from .models import *
from .utils import *
from common.push_git import push_git


class ReadOnlyModelAdmin(admin.ModelAdmin):
    """ModelAdmin class that prevents modifications through the admin.

    The changelist and the detail view work, but a 403 is returned
    if one actually tries to edit an object.
    """

    actions = None

    def get_readonly_fields(self, request, obj=None):
        return self.fields or [f.name for f in self.model._meta.fields]

    def has_add_permission(self, request):
        return False

    # Allow viewing objects but not actually changing them
    def has_change_permission(self, request, obj=None):
        if request.method not in ('GET', 'HEAD'):
            return False
        return super(ReadOnlyModelAdmin, self).has_change_permission(request, obj)

    def has_delete_permission(self, request, obj=None):
        return False


class UserAdmin(admin.ModelAdmin):
    list_display = ('id', 'username', 'email', 'password', 'is_password_set', 'date_joined',
                    'is_staff')
    search_fields = ('username', 'email')
    ordering = ['-id']
    save_on_top = True
    list_per_page = 50


class ProjectGroupAdmin(admin.ModelAdmin):
    list_display = ('id', 'project_name',  'project_note')
    search_fields = ('project_name',)

    ordering = ['-id']
    save_on_top = True
    list_per_page = 50


class ProjectPeopleResource(resources.ModelResource):
    name = fields.Field(column_name='name', attribute='name')
    position = fields.Field(column_name='position', attribute='position')
    id = fields.Field(column_name='id',
            attribute='project',
            widget=ForeignKeyWidget(ProjectGroup, 'id'))

    class Meta:
        model = ProjectPeople
        fields = ()
        import_id_fields = ('name', 'position', 'id')
    
    def import_data(self, dataset, dry_run=False, raise_errors=False,
                    use_transactions=None, **kwargs):
        p = Pinyin()
        result = self.get_result_class()()
        result.diff_headers = self.get_diff_headers()
        result.totals = OrderedDict([(RowResult.IMPORT_TYPE_NEW, 0),
                                     (RowResult.IMPORT_TYPE_UPDATE, 0),
                                     (RowResult.IMPORT_TYPE_DELETE, 0),
                                     (RowResult.IMPORT_TYPE_SKIP, 0),
                                     (RowResult.IMPORT_TYPE_ERROR, 0),
                                     ('total', len(dataset))])
        instance_loader = self._meta.instance_loader_class(self, dataset)
        result.totals['total'] = len(dataset)
        for row in dataset.dict:
            error = ''
            name = row['name'].strip()
            position = row['position']
            id = row['id']
            if name is None or position is None or id is None:
                continue
            try:
                project_name = ProjectGroup.objects.get(id=int(id))
            except ProjectGroup.DoesNotExist:
                error += '项目组{0}不存在！'.format(str(id))
            try:
                project_people = ProjectPeople.objects.get(name=name)
                project_people.project_id = int(id)
                project_people.position = position
                project_people.save()
            except ProjectPeople.DoesNotExist:
                username = p.get_pinyin(name, '')
                #  email = '{0}@tienon.com'.format(username)
                # user = User.objects.create(username=username,
                #                    email=email,
                #                    password='pbkdf2_sha256$150000$lAdJrWNAbkVC$jyI0JfZutg2PLdUCm/tXcbehGxYUKbS5rsAymO7E5+g=',
                #                    is_password_set=True,
                #                    is_staff=True,
                #                    is_superuser=False)
                # user.save()
                ProjectPeople.objects.create(project_id=int(id),
                                     name=name,
                                     attendance_group=username)
            row_result = self.import_row(
                row, instance_loader, dry_run, **kwargs)
            if row_result.errors:
                if error:
                    row_result.errors = []
                    row_result.errors.append(
                        self.get_error_result_class()(error, '', row))
                result.totals[row_result.IMPORT_TYPE_ERROR] += 1
            if (row_result.import_type != RowResult.IMPORT_TYPE_SKIP or
                    self._meta.report_skipped):
                result.rows.append(row_result)
        return result


class ProjectPeopleAdmin(ImportMixin, admin.ModelAdmin):
    actions = ['to_pinyin', ]
    list_display = ('name', 'project', 'attendance_group', 'position')

    search_fields = ('name', 'attendance_group')
    ordering = ['position']
    save_on_top = True
    list_per_page = 50
    resource_class = ProjectPeopleResource

    def to_pinyin(self, request, queryset):
        for res in queryset:
            p = Pinyin()
            result = p.get_pinyin(res.name, '')
            res.attendance_group = result
            res.save()

    def modifly_team(self, request, queryset):
        for res in queryset:
            res.team_type = 1
            res.save()
    to_pinyin.short_description = '生成用户拼音' 
    modifly_team.short_description = '批量修改成员所属小组'


class AttendanceAdmin(admin.ModelAdmin):
    actions = ['export_as_excel']  # 增加动作, 对应相应的方法名
    autocomplete_fields = ['people']
    list_display = ('people', 'project_group', 'attendance_date', 'reason', 'in_date', 'back_date',
                    'note', 'duration')
    radio_fields = {'note': admin.VERTICAL}
    list_filter = (('attendance_date', DateRangeFilter), 'note')
    search_fields = ('people__name', )
    ordering = ['-people__position']
    save_on_top = True
    list_per_page = 50

    def get_queryset(self, request):
        if request.user.id == 2:
            qs = Attendance.objects.filter(attendance_date__gte=date.today() - relativedelta(days=5))
        elif request.user.id in settings.SUPER_ADMIN:
            qs = super(AttendanceAdmin, self).get_queryset(request)
        else:
            qs = Attendance.objects.filter(people__user=request.user)
        return qs

    def get_readonly_fields(self,request,obj=None):
        readonly_field = []
        if request.user.id not in (1, 2):
            for f in self.model._meta.fields:
                if f.name == 'people':
                    readonly_field.append(f.name)
        return readonly_field

    def save_model(self, request, obj, form, change):
        if change:
            obj.save()
            return
        if request.user.id not in (1, 2):
            res = ProjectPeople.objects.get(user=request.user)
        else:
            res = obj.people
        result = Attendance.objects.filter(people=res, attendance_date=obj.attendance_date)
        if len(result) > 0:
            self.message_user(request, '你当天的考勤记录已添加，请勿重复添加记录')
            return
        else:
            if request.user.id not in (1, 2):
                obj.people = res
                obj.save()
            else:
                obj.save()

    def project_group(self, obj):
        return obj.people.project.project_name

    def duration(self, obj):
        return round((parser.parse(str(obj.back_date)) - parser.parse(str(obj.in_date))).seconds / 3600.0, 1)

    def export_as_excel(self, request, queryset):  # 具体的导出csv方法的实现
        meta = self.model._meta
        field_names = []
            # field.name for field in meta.fields
        for field in meta.fields:
            if field.name == 'people':
                field_name = '姓名'
            elif field.name == 'attendance_date':
                field_name = '打卡日期'
            elif field.name == 'in_date':
                field_name = '签到时间'
            elif field.name == 'back_date':
                field_name = '签退时间'
            elif field.name == 'reason':
                field_name = '具体事项'
            elif field.name == 'note':
                field_name = '备注'
            else:
                continue
            field_names.append(field_name)
        field_names.append('加班时长（小时）')
        field_names.append('项目组')
        response = HttpResponse(content_type='application/msexcel')
        response['Content-Disposition'] = f'attachment; filename={meta}.xlsx'
        wb = Workbook()
        ws = wb.active
        ws.append(field_names)
        for obj in queryset:
            data = []
            for field in field_names:
                if field == '姓名':
                    res = obj.people.name
                elif field == '项目组':
                    res = obj.people.project.project_name
                elif field == '打卡日期':
                    res = obj.attendance_date
                elif field == '签到时间':
                    res = obj.in_date
                elif field == '签退时间':
                    res = obj.back_date
                elif field == '具体事项':
                    res = obj.reason
                elif field == '备注':
                    if obj.note == 'M':
                        res = '加班'
                    else:
                        res = '考勤'
                else:
                    res = round((parser.parse(str(obj.back_date)) - parser.parse(str(obj.in_date))).seconds / 3600.0, 1)
                data.append(res)
            ws.append(data)

        wb.save(response)
        return response

    export_as_excel.short_description = '导出Excel'  # 该动作在admin中的显示文字

    duration.short_description = '加班时长(h)'
    project_group.short_description = '项目组'


class WeekContentInline(admin.TabularInline):
    model = WeekContent

    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(WeekContentInline, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'start_time':
            field.initial = return_week_date()
        if db_field.name == 'end_time':
            field.initial = return_week_five_date()
        return field
    extra = 1 #默认显示条目的数量


class NextWeekContentInline(admin.TabularInline):
    model = NextWeekContent

    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(NextWeekContentInline, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'expect_time':
            field.initial = return_next_week_date()
        if db_field.name == 'plan_time':
            field.initial = return_next_five_week_date()
        return field
    extra = 1 #默认显示条目的数量


class WeeklyAdmin(admin.ModelAdmin):
    actions = ['export_as_excel', 'export_month_as_excel', 'export_mine_excel']  # 增加动作, 对应相应的方法名
    inlines = [WeekContentInline, NextWeekContentInline, ]
    autocomplete_fields = ['people']
    list_display = ('people', 'week_content', 'next_week_content', 'update_time')

    list_filter = (('update_time', DateRangeFilter), 
                   'people__team_type',  )
    search_fields = ('people__name', 'people__attendance_group', 'people__project__project_name')
    ordering = ['people__position']
    # radio_fields = {'people__team_type': admin.VERTICAL}
    save_on_top = True
    list_per_page = 50

    def get_actions(self, request):
        actions = super().get_actions(request)
        if not request.user.is_leader:
            if 'export_month_as_excel' in actions:
                del actions['export_month_as_excel']
        if request.user.id not in(1, 2):
            if 'export_as_excel' in actions:
                del actions['export_as_excel']
        return actions

    def get_queryset(self, request):
        if request.user.id == 2:
            # 超级用户和公用账号返回所有数据
            qs = Weekly.objects.filter(update_time__gte=date.today() - relativedelta(days=4))
        elif request.user.id in (1, 78):
            qs = Weekly.objects.all()
        elif request.user.is_leader:
            # 组长返回其所在组的组员当月所有的周报
            project_people = ProjectPeople.objects.get(user=request.user)
            qs = Weekly.objects.filter(people__project=project_people.project,
                                       update_time__gte=date.today() - relativedelta(days=90))
        else:
            # 单用户返回当前用户的周报
            qs = Weekly.objects.filter(people__user=request.user)
        return qs

    def get_readonly_fields(self,request,obj=None):
        readonly_field = []
        if request.user.id not in (1, 2):
            for f in self.model._meta.fields:
                if f.name == 'people':
                    readonly_field.append(f.name)
        return readonly_field

    def save_model(self, request, obj, form, change):
        if request.user.id not in (1, 2):
            res = ProjectPeople.objects.get(user=request.user)
            obj.people = res
            obj.save()
        else:
            obj.save()

    def week_content(self, obj):
        try:
            result = WeekContent.objects.filter(week_weekly=obj.id).first()
            qs = result.week_content
        except (WeekContent.DoesNotExist, AttributeError):
            qs = ''
        return qs

    def next_week_content(self, obj):
        try:
            result = NextWeekContent.objects.filter(net_week_weekly=obj.id).first()
            qs = result.next_week_content
        except (NextWeekContent.DoesNotExist, AttributeError):
            qs = ''
        return qs

    def export_as_excel(self, request, queryset):
        meta = self.model._meta
        response = HttpResponse(content_type='application/msexcel')
        response['Content-Disposition'] = f'attachment; filename={meta}.xlsx'
        wb = Workbook()
        ws = wb.active
        ws.merge_cells('A1:K4')
        ws.cell(1, 1).value = '厦开项目组周报   （周期：-）'
        ws.cell(5, 4).value = '项目主管：'
        ws.cell(5, 6).value = '项目主管评价：'
        field_names = ['', '序号', '项目名称', '责任人', '工作事项名称', '开始时间', '完成时间',
                       '计划%', '实际%', '偏差%', '进展说明', ]
        ws.append(field_names)

        # 本周需要合并的行数
        con = 0
        # 序号
        count = 0
        # 起始行数
        first_count = 6
        for obj in queryset:
            results = WeekContent.objects.filter(week_weekly=obj.id)
            count += 1

            # 序号需要合并的行数
            no_count = 0
            for result in results:
                if result.week_content == '' or result.week_content is None:
                    continue
                no_count += 1
                con += 1
                res = ['', '', obj.people.project.project_name, obj.people.name, result.week_content, result.start_time,
                       result.end_time, result.plan, result.actual, result.deviation,
                       result.progress_desc]
                ws.append(res)
            if no_count == 0:
                con -= 1
                continue
            ws.merge_cells('B{0}:B{1}'.format(str(first_count+1), str(first_count+no_count)))
            ws.cell(first_count+1, 2).value = count
            first_count +=  no_count
        con = 6 + con
        ws.merge_cells('A6:{0}'.format(('A'+str(con))))
        ws.cell(6, 1).value = '一.本周计划进展情况'

        next_field_names = ['', '序号', '项目名称', '责任人', '工作事项名称', '开始时间', '结束时间', '', '', '' '说明']
        ws.append(next_field_names)
        # 需要合并的总行数
        no_next_count = 0
        # 起始行数
        next_count = 0
        cons = con+1
        ws.merge_cells('H{0}:J{1}'.format(str(cons), str(cons)))
        ws.cell(cons, 8).value = '计划输出结果'
        ws.cell(cons, 11).value = '说明'
        for obj in queryset:
            results = NextWeekContent.objects.filter(net_week_weekly=obj.id)
            next_count += 1
            # 序号需要合并的行数
            rows = 0
            for result in results:
                if result.next_week_content == '' or result.next_week_content is None:
                    continue
                rows += 1
                no_next_count += 1
                res = ['', next_count, obj.people.project.project_name, obj.people.name, result.next_week_content,
                       result.expect_time, result.plan_time, '', '']
                ws.append(res)
                ws.merge_cells('H{0}:J{1}'.format(str(cons+rows), str(cons+rows)))
                ws.cell(cons+rows, 8).value = result.result
                ws.cell(cons + rows, 11).value = result.note
            if rows == 0:
                next_count -= 1
                continue
            ws.merge_cells('B{0}:B{1}'.format(str(cons+1), str(cons+rows)))
            ws.cell(cons+1, 2).value = next_count
            cons += rows
        ws.merge_cells('A{0}:A{1}'.format(str(con+2), str(con+1+no_next_count)))
        ws.cell(con+2, 1).value = '二、下周工作计划'

        fields = ['', '序号', '问题名称', '', '', '提出日期', '提出人团队', '解决责任团队', '预期解决时间', '解决建议方案和计划',
                  '解决建议方案和计划']
        ws.append(fields)
        con = con+1+no_next_count+2
        ws.merge_cells('D{0}:E{1}'.format(str(con), str(con)))
        ws.cell(con, 4).value = '问题描述'
        ws.merge_cells("A{0}:A{1}".format(str(con), str(con+10)))
        ws.cell(con, 1).value = '三.目前存在的问题以及需要协调解决的事项'

        con2 = con + 11
        ws.merge_cells('C{0}:D{1}'.format(str(con2), str(con2)))
        ws.cell(con2, 2).value = '序号'
        ws.cell(con2, 3).value = '进展说明'
        ws.merge_cells("A{0}:A{1}".format(str(con2), str(con2+10)))
        ws.cell(con2, 1).value = '四.本周质量管理方面的工作总结'

        con3 = con2 + 11
        ws.merge_cells('C{0}:D{1}'.format(str(con3), str(con3)))
        ws.cell(con3, 2).value = '序号'
        ws.cell(con3, 3).value = '进展说明'
        ws.merge_cells("A{0}:A{1}".format(str(con3), str(con3 + 10)))
        ws.cell(con3, 1).value = '五.本周配置管理方面的工作总结'

        wb.save(response)
        return response

    def export_month_as_excel(self, request, queryset):
        meta = self.model._meta
        response = HttpResponse(content_type='application/msexcel')
        response['Content-Disposition'] = f'attachment; filename={meta}.xlsx'
        wb = Workbook()
        ws = wb.active
        next_field_names = ['序号', '工作事项名称', '开始时间', '完成时间', '责任人', '计划%', '实际%', '偏差%', '进展说明']
        ws.append(next_field_names)
        num = 1
        for obj in queryset:
            results = WeekContent.objects.filter(week_weekly=obj.id)
            for result in results:
                res = [num, result.week_content, result.start_time, result.end_time, obj.people.name, result.plan, result.actual, result.deviation, result.progress_desc]
                ws.append(res)
                num += 1
        wb.save(response)
        return response


    def export_mine_excel(self, request, queryset):
        meta = self.model._meta
        response = HttpResponse(content_type='application/msexcel')
        response['Content-Disposition'] = f'attachment; filename={meta}.xlsx'
        wb = Workbook()
        ws = wb.active
        next_field_names = ['序号', '工作事项名称', '开始时间', '完成时间', '责任人', '计划%', '实际%', '偏差%', '进展说明']
        ws.append(next_field_names)
        num = 1
        for obj in queryset:
            results = WeekContent.objects.filter(week_weekly=obj.id)
            for result in results:
                res = [num, result.week_content, result.start_time, result.end_time, obj.people.name, result.plan, result.actual, result.deviation, result.progress_desc]
                ws.append(res)
                num += 1
        wb.save(response)
        return response

    week_content.short_description = '本周工作内容简述'
    next_week_content.short_description = '下周工作计划简述'
    export_as_excel.short_description = '导出周报'  # 该动作在admin中的显示文字
    export_month_as_excel.short_description = '导出组员月报'
    export_mine_excel.short_description = '导出个人月报'


class GitPushFileAdmin(admin.ModelAdmin):
    actions = ['push_git_api']  # 增加动作, 对应相应的方法名
    list_display = ('file_upload', )

    ordering = ['-id']
    save_on_top = True
    list_per_page = 50

    def get_queryset(self, request):
        qs = super(GitPushFileAdmin, self).get_queryset(
            request).order_by('-id')
        return qs

    def push_git_api(self, request, queryset):
        for obj in queryset:
            print(obj.id, obj.file_upload)
            cmd = '{0}{1}'.format(settings.FILE_URL, str(obj.file_upload)[5:])
            cmds = 'cp {0}  {1}'.format(cmd, settings.GIT_FILE_URL)
            print(cmds)
            push_git(cmds)
        pass

    push_git_api.short_description = '提交周报'

admin.site.register(User, UserAdmin)
admin.site.register(ProjectGroup, ProjectGroupAdmin)
admin.site.register(ProjectPeople, ProjectPeopleAdmin)
admin.site.register(Attendance, AttendanceAdmin)
admin.site.register(Weekly, WeeklyAdmin)
admin.site.register(GitPushFile, GitPushFileAdmin)
